﻿#region Header
// ------------------------ Licence / Copyright ------------------------
// 
// ScrumTable for Scrum Meeting Support
// Copyright © HSR - Hochschule für Technik Rapperswil
// All Rights Reserved
// 
// Author:
//  Michael Gfeller Silvan Gehrig Patrick Boos
// 
// ---------------------------------------------------------------------
#endregion

#region Usings

using System;
using System.Collections.Generic;
using System.Xml;
using ScrumTable.Common;
using ScrumTable.Common.Logging;
using ScrumTable.Common.Security;

#endregion

namespace ScrumTable.DL.Data.TFS.Services.SharePoint
{
    /// <summary>
    /// This class is used in order to connect to the Microsoft
    /// Windows SharePoint and its user list.
    /// </summary>
    /// <remarks>
    /// All operations on this instance will invoke the underlying WSS
    /// instance.
    /// </remarks>
    public class WssUserList
    {
        #region Declarations
        //--------------------------------------------------------------------
        // Declarations
        //--------------------------------------------------------------------

        private const int RequestTimeout = 20000; // ms
        private const string UserListName = "UserInfo";
        private const string ListServicePath = "_vti_bin/Lists.asmx"; // see <http://msdn.microsoft.com/en-us/library/lists.aspx>

        private static readonly XmlDocument ListConfiguration;

        private readonly ConnectionInformation _connectionCtx;
        private readonly char[] _pictureSeparator = { ',' };

        #endregion

        #region Properties
        //--------------------------------------------------------------------
        // Properties
        //--------------------------------------------------------------------

        #endregion

        #region Constructors / Destructor
        //--------------------------------------------------------------------
        // Constructors / Destructor
        //--------------------------------------------------------------------

        /// <summary>
        /// Init immutable xml document.
        /// </summary>
        static WssUserList()
        {
            // load configuration xml file with protocol information
            ListConfiguration = new XmlDocument();
            ListConfiguration.LoadXml(Properties.Resources.WssUserList);
        }

        /// <summary>
        /// Creates a new WssUserList instance. This constructor is used in
        /// the current library only.
        /// </summary>
        /// <param name="connectionCtx">
        ///     <attribute ctor="M:JetBrains.Annotations.NotNullAttribute.#ctor" />
        /// </param>
        internal WssUserList(ConnectionInformation connectionCtx)
        {
            PreCondition.AssertNotNull(connectionCtx, "connectionCtx");

            _connectionCtx = connectionCtx;
        }

        #endregion

        #region Methods
        //--------------------------------------------------------------------
        // Methods
        //--------------------------------------------------------------------

        /// <summary>
        /// Makes sure that the user list is available on the WSS side.
        /// </summary>
        /// <param name="wssUri">Specifies the sharepoint uri.</param>
        /// <returns>Returns the list version which is required to update the list.</returns>
        internal string Connect(Uri wssUri)
        {
            PreCondition.AssertNotNull(wssUri, "wssUri");
            
            string listVersion = null;

            using (Lists.Lists listsService = GetWebService(wssUri))
            {
                XmlNode foundData = listsService.GetList(UserListName);
                listVersion = (foundData.Attributes["Version"] != null) ? foundData.Attributes["Version"].Value : null;

                Logger<WssUser>.DebugFormat(Properties.Resources.LogUserListFound, foundData.OuterXml);
            }
            return listVersion;
        }

        /// <summary>
        /// Retreives all users from the underlying sharepoint dictionary indexed by its ID.
        /// </summary>
        /// <param name="wssUri">Specifies the sharepoint uri.</param>
        internal IDictionary<string, WssUser> Get(Uri wssUri)
        {
            PreCondition.AssertNotNull(wssUri, "wssUri");

            IDictionary<string, WssUser> retreivedData = new Dictionary<string, WssUser>(0);

            using (Lists.Lists listsService = GetWebService(wssUri))
            {
                XmlNode resultData = listsService.GetListItems(
                    UserListName,
                    string.Empty,
                    null,
                    SelectConfigurationNode("/ListCommand/Get/ViewFields"),
                    null,
                    null,
                    null);
                Logger<WssUser>.DebugFormat(Properties.Resources.LogUserListGetData, resultData.OuterXml);

                XmlNamespaceManager nsmgr = new XmlNamespaceManager(resultData.OwnerDocument.NameTable);
                nsmgr.AddNamespace("z", "#RowsetSchema");
                XmlNodeList elements = resultData.SelectNodes("//z:row", nsmgr);

                if (elements == null)
                    throw new WssException(string.Empty);

                retreivedData = new Dictionary<string, WssUser>(elements.Count);

                foreach (XmlNode node in elements)
                {
                    if (node.Attributes["ows_Name"] != null)
                    {
                        string id = node.Attributes["ows_Name"].Value.ToLowerInvariant();
                        string[] pictures = ((node.Attributes["ows_Picture"] != null)
                                             ? node.Attributes["ows_Picture"].Value
                                             : string.Empty).Split(_pictureSeparator);

                        retreivedData.Add(id, new WssUser(id, pictures[0].Trim()));
                    }
                }
            }
            return retreivedData;
        }

        private Lists.Lists GetWebService(Uri wssUri)
        {
            // for ssl see http://msdn.microsoft.com/en-us/library/system.net.servicepointmanager.servercertificatevalidationcallback.aspx
            Lists.Lists webService = new Lists.Lists();
            webService.Url = wssUri.ReplacePath(ListServicePath).ToString();
            webService.Credentials = _connectionCtx.NetworkCredentials;
            webService.Timeout = RequestTimeout;
            return webService;
        }

        private XmlNode SelectConfigurationNode(string xPath)
        {
            return ListConfiguration.SelectSingleNode(xPath).CloneNode(true);
        }

        #endregion

        #region Events
        //--------------------------------------------------------------------
        // Events
        //--------------------------------------------------------------------

        #endregion
    }
}
